package com.sunriz.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sunriz.domain.SpaEntity;
import com.sunriz.domain.SpaProperty;
import com.sunriz.domain.SpaResult;
import com.sunriz.domain.UpdateObject;
import com.sunriz.mapper.CtrlMapper;
import com.sunriz.service.CtrlService;
import com.sunriz.spa.PropertyUtils;
import com.sunriz.spa.SpaUtils;
import lombok.extern.slf4j.Slf4j;
import net.e175.klaus.solarpositioning.AzimuthZenithAngle;
import org.apache.poi.ss.formula.functions.IfFunc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @author: 童锣烧
 * @time: 2023/11/09
 */
@Slf4j
@Service
public class CtrlServiceImpl implements CtrlService {

    @Autowired
    private RedisTemplate redisTemplate;
//    @Autowired
//    @Qualifier(value = "redisTemplate2")
//    private RedisTemplate redisTemplate2;
    @Autowired
    private CtrlMapper ctrlMapper;
    private List<SpaResult> spareSult;

    /**
     * 查找hc控制器中地理纬度、地理经度、海拔高度、年平均压力、年平均温度的值
     * @return
     */
    @Override
    public List<SpaResult> select() {
        return ctrlMapper.select();
    }

    @Override
    public JSONObject update(String tdCode, String deviceCode, String param) {
        JSONObject jsonObject= JSON.parseObject(param);
        JSONObject dataObject=jsonObject.getJSONObject("data");

        for(String key: dataObject.keySet()){
            String value= (String) dataObject.get(key);
            ctrlMapper.update(deviceCode,key,value);
        }
        return dataObject;
    }


    /**
     * without: 层级下发
     * @param tdCode
     * @param deviceCode
     * @param param
     * @return
     */
//    @Override
//    public JSONObject update(String tdCode, String deviceCode, String param) {
//        //下发父列表
//        ArrayList<UpdateObject> faUpdateList = new ArrayList<>();
//        //遍历param参数，将该条key-value数据生成下发子列表，并添加到父列表
//        JSONObject jsonObject= JSON.parseObject(param);
//        JSONObject dataObject=jsonObject.getJSONObject("data");
//        for(String key: dataObject.keySet()){
//            ArrayList sonUpdateList=new ArrayList<>();
//            faUpdateList.addAll(genSonUpdateList(sonUpdateList,tdCode,deviceCode,key, (String) dataObject.get(key)));
//        }
//        update2Ctrl(faUpdateList);
//        return dataObject;
//    }


    /**
     * 生成下发列表
     * @param tdCode :设备类型
     * @param deviceCode :设备编号
     * @param propertKey :下发key
     * @param propertValue :下发value
     */
    public List<UpdateObject> genSonUpdateList(List<UpdateObject> sonUpdateList,String tdCode, String deviceCode, String propertKey, String propertValue){

        //将当前信息下发
        UpdateObject updateObject = new UpdateObject(deviceCode,propertKey,propertValue);
        //添加到下发列表
        sonUpdateList.add(updateObject);

        System.out.println(updateObject.getDeviceCode());


        //Case1:该key是mc下发到cc的情况
        if(tdCode.equals("mc")&&PropertyUtils.isA(propertKey)){
            //查询子cc的deviceCode，遍历生成这些cc的下发列表
            List<String> sonDeviceCodes = new ArrayList<>();
            sonDeviceCodes=ctrlMapper.selectF2S(deviceCode);
            for(String device:sonDeviceCodes){
                //递归调用
                genSonUpdateList(sonUpdateList,"cc",device,propertKey,propertValue);
            }
        }

        //Case2:该key是mc下发到hc的情况
        if(tdCode.equals("mc")&&PropertyUtils.isB(propertKey)){
            //查询子hc的deviceCode
            List<String> sonDeviceCodes = new ArrayList<>();
            //第一次查到的结果
            List<String> sonDeviceCode1 = new ArrayList<>();
            //第二次查到的结果
            List<String> sonDeviceCode2 = new ArrayList<>();

            sonDeviceCode1=ctrlMapper.selectF2S(deviceCode);

            for(String deviceCodes:sonDeviceCode1){
                sonDeviceCode2=ctrlMapper.selectF2S(deviceCodes);
                sonDeviceCodes.addAll(sonDeviceCode2);
            }


            for(String device:sonDeviceCodes){
                //递归调用
                genSonUpdateList(sonUpdateList,"hc",device,propertKey,propertValue);
            }
        }

        //Case3:该key是cc下发到hc的情况
        if(tdCode.equals("cc")&&PropertyUtils.isA(propertKey)||tdCode.equals("cc")&&PropertyUtils.isC(propertKey)){
            //查询子hc的deviceCode
            List<String> sonDeviceCodes = new ArrayList<>();
            sonDeviceCodes=ctrlMapper.selectF2S(deviceCode);
            for(String device:sonDeviceCodes){
                //递归调用
                genSonUpdateList(sonUpdateList,"hc",device,propertKey,propertValue);
            }
        }
        return sonUpdateList;
    }

    /**
     * 下发数据到控制器(延时下发)
     * @param list :下发列表
     */
    @Override
    public void update2Ctrl(List<UpdateObject> list) {
        for (int i = 0; i < list.size(); i++) {
            //i除以10的商 然后将商加1,最后乘以2。根据索引i来计算时间间隔
            int delay = (i / 10 + 1) * 2;
            try {
                Thread.sleep(delay);
                UpdateObject oneList = list.get(i);
                ctrlMapper.update(oneList.getDeviceCode(), oneList.getKey(), oneList.getValue());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 定时运行SPA算法
     * @throws Exception
     *
     */
    @Override
    public void runSPA()  throws Exception{

        double start = System.currentTimeMillis();

        ValueOperations valueOperations = redisTemplate.opsForValue();
        LocalDateTime time = LocalDateTime.now();

        //获取所有的key，不建议用keys("*")
        RedisConnection connection = redisTemplate.getRequiredConnectionFactory().getConnection();
        ScanOptions scanOptions = new ScanOptions.ScanOptionsBuilder()
                .count(10000)
                .match("*")
                .build();
        Cursor<byte[]> cursor = connection.scan(scanOptions);
        List<String> keys = new ArrayList<>();
        while (cursor.hasNext()) {
            String key = new String(cursor.next(), StandardCharsets.UTF_8);
            keys.add(key);
        }

        //对每个hc进行计算，并且写入到redis
        for (String key : keys) {

            List<SpaProperty> properties =(List<SpaProperty>) valueOperations.get(key);

            AzimuthZenithAngle res = SpaUtils.getAzimuthAndZenithAngle(time, ZoneId.of("Asia/Shanghai"), Double.valueOf(properties.get(3).getPropertyValue())
                    , Double.valueOf(properties.get(4).getPropertyValue()), Double.valueOf(properties.get(2).getPropertyValue())
                    , Double.valueOf(properties.get(0).getPropertyValue()), Double.valueOf(properties.get(1).getPropertyValue()));

            properties.get(5).setPropertyValue(String.valueOf(90 - res.getZenithAngle()));
            properties.get(6).setPropertyValue(String.valueOf(res.getAzimuth()));

            redisTemplate.opsForValue().set(key,properties);
        }

         log.info("redis更新数据耗时："+(System.currentTimeMillis()-start));
    }
}
